﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Crm2011.Framework.Core;
using Infragistics.Win.UltraWinGrid;



namespace ScriptEase.Shell.Controls
{
    /// <summary>
    /// </summary>
    public partial class WebResourceStatusView : UserControl
    {
        public WebResourceStatusView()
        {
            InitializeComponent();
        }



        public MappingList List
        {
            private get { return _list; }
            set
            {
                if (_list == value) return;
                // got a new list
                if (_list != null)
                { // unregister previous list   
                    _list.CollectionUpdate -= listCollectionUpdate;
                    _list.CollectionChanged -= listCollectionChanged;
                    _list.ItemPropertyChanged -= listItemPropertyChanged;
                    _list = null;
                }
                if (value == null) return;

                // bind new list
                _list = value;
                _list.CollectionUpdate += listCollectionUpdate;
                _list.CollectionChanged += listCollectionChanged;
                _list.ItemPropertyChanged += listItemPropertyChanged;
            }
        }
        private MappingList _list;



        /// <summary>
        /// An item was added/removed or the list was cleared.
        /// </summary>
        /// <remarks>
        /// Update Grid accordingly.
        /// </remarks>
        private void listCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    foreach (object newItem in e.NewItems)
                    {
                        addItemToGrid((MappingModel)newItem);
                    }
                    break;
                case NotifyCollectionChangedAction.Reset:
                    clearGrid();
                    break;
                //case NotifyCollectionChangedAction.Remove:
                //case NotifyCollectionChangedAction.Replace:
                //case NotifyCollectionChangedAction.Move:
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }


        // listCollection... refers to the collection itself
        // listItem... refers to a single item in the list

        /// <summary>
        /// An batch update has been started or ended on the list.
        /// </summary>
        void listCollectionUpdate(object sender, CollectionUpdateEventHandlerArgs e)
        {
            switch (e.Action)
            {
                case CollectionUpdateAction.BeginUpdate:
                    this.ultraGrid1.BeginUpdate();
                    break;
                case CollectionUpdateAction.EndUpdate:
                    //No more used because this column is always visible
                    //UltraGridColumn col = this.ultraGrid1.DisplayLayout.Bands[0].Columns["IsManaged"];
                    //if (col.Hidden)
                    //{
                    //    bool needManagedColumn = this.gridTable.AsQueryable().Any(row => row.IsManaged);
                    //    col.Hidden = !needManagedColumn;
                    //}
                    //else col.Hidden = true;
                    this.ultraGrid1.EndUpdate();
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }


        /// <summary>
        /// A Grid item's underlying list item (the MappingModel) has been changed.
        /// </summary>
        private void listItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            updateGridItem((MappingModel)sender);
        }



        /// <summary>
        /// An UltraGrid rows content has been changed.
        /// </summary>
        private void ultraGrid1AfterRowUpdate(object sender, RowEventArgs e)
        {
            ControlBindingDataSet.GridDataRow row = getGridDataRow(e.Row);
            if (row == null) return;
            MappingModel mapping = this.List.FirstOrDefault(item => item.Id == row.Id);
            if (mapping == null) return;
            mapping.AutoUpdate = row.AutoUpdate;
        }




        #region Update Grid methods


        private void clearGrid()
        {
            try
            {
                this.ultraGrid1.BeginUpdate();
                this.gridTable.Clear();
            }
            catch (Exception e)
            {
                Trace.Default.LogException(e);
            }
            finally
            {
                this.ultraGrid1.EndUpdate();
            }
        }



        private void addItemToGrid(MappingModel mappingModel)
        {
            try
            {
                Trace.Default.Debug("Grid item added {0}", mappingModel.WebResourceName);
                ControlBindingDataSet.GridDataRow gridDataRow = this.gridTable.NewGridDataRow();
                listItemToGridRow(mappingModel, gridDataRow);
                this.gridTable.AddGridDataRow(gridDataRow);
                gridDataRow.AcceptChanges();
                setRowColor(gridDataRow);
                updateToolStrip();
            }
            catch (Exception ex)
            {
                Trace.Default.LogException(ex);
            }
        }



        private void updateGridItem(MappingModel mappingModel)
        {
            try
            {
                Trace.Default.Debug("Grid item changed {0}", mappingModel.WebResourceName);
                ControlBindingDataSet.GridDataRow gridDataRow = getGridDataRow(mappingModel.Id);
                listItemToGridRow(mappingModel, gridDataRow);
                gridDataRow.AcceptChanges();
                setRowColor(gridDataRow);
                updateToolStrip();
            }
            catch (Exception ex)
            {
                Trace.Default.LogException(ex);
            }
        }

        #endregion



        public IEnumerable<MappingModel> SelectedItems
        {
            get
            {
                List<MappingModel> result
                    = (from UltraGridRow selectedRow in this.ultraGrid1.Selected.Rows
                       where selectedRow.IsDataRow
                       select getGridListItem(selectedRow)).ToList();

                if (!result.Any() && gridBindingSource.Current != null)
                {
                    // nothing selected, do we have a current instead?
                    var currentMapping = getGridListItem((DataRowView)gridBindingSource.Current);
                    if (currentMapping != null) result.Add(currentMapping);
                }
                return result;
            }
        }



        #region Grid Data Table

        private MappingModel getGridListItem(UltraGridRow ultraGridRow)
        {
            return ultraGridRow == null ? null : getGridListItem((DataRowView)ultraGridRow.ListObject);
        }

        private MappingModel getGridListItem(DataRowView rowView)
        {
            return rowView == null ? null : getGridListItem(rowView.Row);
        }

        private MappingModel getGridListItem(DataRow row)
        {
            return this.List.FirstOrDefault(r => r.Id == (Guid)row["Id"]);
        }


        /// <summary>
        /// Get the DataTable that is bound to the Grid.
        /// </summary>
        private ControlBindingDataSet.GridDataDataTable gridTable
        {
            get { return controlBindingDataSet.GridData; }
        }


        //
        // Get information from Grid
        //

        private UltraGridRow getUltraGridRow(object gridDataRow)
        {
            return gridDataRow == null ? null : ultraGrid1.Rows.FirstOrDefault(ugr => gridDataRow.Equals(getGridDataRow(ugr)));
        }



        private ControlBindingDataSet.GridDataRow getGridDataRow(UltraGridRow ultraGridRow)
        {
            // when grouping is enabled ListObject can be null!
            return getGridDataRow((DataRowView)ultraGridRow.ListObject);
        }


        private ControlBindingDataSet.GridDataRow getGridDataRow(DataRowView rowView)
        {
            if (rowView == null) return null;
            return (ControlBindingDataSet.GridDataRow)rowView.Row;
        }


        private ControlBindingDataSet.GridDataRow getGridDataRow(Guid id)
        {
            return (ControlBindingDataSet.GridDataRow)this.gridTable.Rows.Find(id);
        }

        #endregion



        private void listItemToGridRow(MappingModel listItem, ControlBindingDataSet.GridDataRow gridDataRow)
        {
            gridDataRow.Id = listItem.Id;
            gridDataRow.WebResourceName = listItem.WebResourceName;
            gridDataRow.FilePath = listItem.FileRelativePath;      // listItem.FileInfo.DirectoryName contains full directory (not wanted)
            gridDataRow.FileName = listItem.FileInfo != null ? listItem.FileInfo.Name : String.Empty;
            gridDataRow.FileExtension = listItem.FileInfo != null ? listItem.FileInfo.Extension : String.Empty;
            gridDataRow.AutoUpdate = listItem.AutoUpdate;
            gridDataRow.FileDate = (listItem.FileInfo == null) ? DateTime.MinValue : listItem.FileInfo.LastWriteTime;
            gridDataRow.SyncStatus = listItem.SyncStatus.ToString();
            gridDataRow.IsManaged = listItem.IsManaged;
            gridDataRow.IsCustomizable = listItem.IsCustomizable;
        }



        private void setRowColor(ControlBindingDataSet.GridDataRow gridDataRow)
        {
            UltraGridRow gridRow = getUltraGridRow(gridDataRow);
            if (gridRow == null) return;

            switch (EnumHelper<FileSyncStatus>.GetEnumItem(gridDataRow.SyncStatus))
            {
                case FileSyncStatus.FileNotDownloaded:
                    gridRow.Appearance.BackColor = Color.Orange;
                    break;
                case FileSyncStatus.FileNotInCrm:
                    gridRow.Appearance.BackColor = Color.LightGray;
                    break;
                case FileSyncStatus.Conflict:
                    gridRow.Appearance.BackColor = Color.LightSalmon;
                    break;
                case FileSyncStatus.PendingUpdate:
                    gridRow.Appearance.BackColor = Color.LightGreen;
                    break;
                case FileSyncStatus.Updating:
                    gridRow.Appearance.BackColor = Color.PaleTurquoise;
                    break;
                case FileSyncStatus.PendingPublish:
                    gridRow.Appearance.BackColor = Color.LightBlue;
                    break;
                case FileSyncStatus.Publishing:
                    gridRow.Appearance.BackColor = Color.PaleTurquoise;
                    break;
                case FileSyncStatus.Published:
                    gridRow.Appearance.BackColor = (gridDataRow.FileDate.Date == DateTime.Now.Date ? Color.GhostWhite : Color.White);
                    break;
            }

            gridRow.Appearance.ForeColor = (gridDataRow.AutoUpdate) ? Color.Black : Color.Gray;
        }


        #region Update Grid's Status bar

        private void ultraGrid1AfterSelectChange(object sender, AfterSelectChangeEventArgs e)
        {
            updateToolStrip();
        }

        private void gridBindingSourcePositionChanged(object sender, EventArgs e)
        {
            updateToolStrip();
        }

        private void updateToolStrip()
        {
            #region Thread-safe invoke


            if (this.ultraGrid1.InvokeRequired)
            {
                this.ultraGrid1.Invoke(new MethodInvoker(updateToolStrip));
                return;
            }


            #endregion


            int selectedCount = this.ultraGrid1.Selected.Rows.Count;
            if (selectedCount == 0 &&
                (this.ultraGrid1.Selected.Columns.Count != 0 || this.ultraGrid1.Selected.Cells.Count != 0) &&
                gridBindingSource.Current != null) selectedCount = 1;

            this.toolStripStatusLabel1.Text =
                string.Format("Rows={0} selected={1}", ultraGrid1.Rows.Count, selectedCount);
        }

        #endregion

    }
}